//------------------------------------------------------------------------------
//	 AdjacencyListGraph.hh
//
//------------------------------------------------------------------------------
// $Id: //CBT-depot/CompBioToolsApps/kjd-apps/atlas/utility/AdjacencyListGraph.hh#3 $
//------------------------------------------------------------------------------
// $Log:$
//==============================================================================
//.......1.........2.........3.........4.........5.........6.........7.........8
//

#ifndef _SPARSE_GRAPH
#define _SPARSE_GRAPH

#include "LocalSTL.hh"
#include "Table.hh"
#include "CLibraryAdditions.hh"
#include "FileUtils.hh"
#include "HashUtils.hh"

//------------------------------------------------------------------------------
// * AlignmentEdgeWt
//------------------------------------------------------------------------------
//
class AlignmentEdgeWt{
public:
  // Save Span[0-1000], Score[-2000,1000], LE[-1000,1000], RE[-1000,1000],f/r
  // Later will replace this with a space efficient version, but for now just
  // save as ints. 
  int mSpan;
  int mScore;
  int mLE;
  int mRE;
  char mSense;
	int mFreq;

  void SetSpan(int span){mSpan = span;};
  void SetScore(int score){mScore = score;};
  void SetLE(int le){mLE = le;};
  void SetRE(int re){mRE = re;};
  void SetSense(char sense){mSense = sense;};
  void SetFreq(int freq){mFreq = freq;};

  int  GetSpan(){return(mSpan);};
  int  GetScore(){return(mScore);};
  int  GetLE(){return(mLE);};
  int  GetRE(){return(mRE);};
  char GetSense(){return(mSense);};
  int  GetFreq(){return(mFreq);};

  // Parses the portion of the string specified to extract edge weight info. 
  // The general format is Node   Node Wt  Node Wt Node Wt
  // Wt can be an arbitrary string with no whitespace, and it will be passed to this
  // function to extract the edge weights. 
  
  // {Span,Score,LE,RE,Sense}
  bool Parse(string &temp){
	 //cout<<"Parse "<<temp<<endl;

	 int offset = 0;
	 mSpan = GetNextInteger(temp,offset,offset);
	 mScore = GetNextInteger(temp,offset,offset);
	 mLE = GetNextInteger(temp,offset,offset);
	 mRE = GetNextInteger(temp,offset,offset);	 
	 string senseStr = temp.substr(offset+1,1);
	 mSense = senseStr[0];
	 mFreq = GetNextInteger(temp,offset+3,offset);
		
	 //cout<<mSpan<<"\t"<<mScore<<"\t"<<mLE<<"\t"<<mRE<<"\t"<<mSense<<"\t"<<mFreq<<endl;
		
	 return(true);
  }

  // Convert the edge weights to a string. 
  string ToString(){
	 char buf[500];
	 sprintf(buf,"{%d,%d,%d,%d,%c,%d}",mSpan,mScore,mLE,mRE,mSense,mFreq);
	 string temp = buf;
	 return(temp);
  }

};

//------------------------------------------------------------------------------
// * ALGEdge
//------------------------------------------------------------------------------
//
template<class T>
class ALGEdge {
public:

  ALGEdge<T>(){
	 mNodeIdx = -1;
  }

  int mNodeIdx;
  T   mEdgeWeight;

  bool Parse(string &temp){
	 bool status = mEdgeWeight.Parse(temp);
	 return(status);
  }

};

//------------------------------------------------------------------------------
// * ALGNode
//------------------------------------------------------------------------------
//
template<class T>
class ALGNode {
public:
  //ALGEdgeNameHash mEdgeNameHash;
  string              mName;
  vector<ALGEdge<T> > mEdges;
};


//------------------------------------------------------------------------------
// * AdjacencyListGraph
//------------------------------------------------------------------------------
// Graphs differ mainly in the type of edge weights, so this is made a template
// class and the edge weight class is specified when it is instantiated. 
//
//
template<class T>
class AdjacencyListGraph{
public:
  
  vector<ALGNode<T> > mNodes;
  String2IntMap mNodeName2IdxMap;

  // Takes a line from a file and an offset marking the beginning of a list 
  // of edges and parses the edge information from the line.   This function is here 
  // and not in ALGNode because it needs to access mNodeNameHas in order to translate 
  // NodeNames to NodeIdx (could have passed in the hash, of course, but this seems more natural)
  // Interesting idea, that, "natural" in the context of programming.  
  void AddEdges(ALGNode<T> &Node,string &line,int offset){
	 string nodeName,edgeWt;
	 do{
		 //cout<<"Add Edges loop."<<endl;
		// KJD Should really check to see if nodeName already is an edge before adding
		 nodeName = SplitNext(line,offset);

		 //	 cout<<"AddEdges nodeName="<<nodeName<<" offset="<<offset<<endl;

		 if (offset >=0){
			 edgeWt = SplitNext(line,offset);
			 int newEdgeIdx = Node.mEdges.size();
			 Node.mEdges.resize(newEdgeIdx+1);
			 int nodeIdx = mNodeName2IdxMap.GetValue(nodeName);
			 Node.mEdges[newEdgeIdx].mNodeIdx = nodeIdx;
			 Node.mEdges[newEdgeIdx].mEdgeWeight.Parse(edgeWt);			 
		 }
	 }while((offset >=0) && (offset < (line.size())));	 
  }

  // Parse a line in the text representation of an ALG and add it to the 
  // current graph.  The nodes listed on the line may or may not already exist. 
  void AddLine(string &line){
		//cout<<"AddLine line "<<line<<endl;
	 string nodeName;
	 int offset = 0;
	 nodeName = SplitNext(line,offset);
	 // If the node exists already, just add new edges to it....
	 if(mNodeName2IdxMap.Contains(nodeName)){
		int nodeIdx = mNodeName2IdxMap.GetValue(nodeName);
		AddEdges(mNodes[nodeIdx],line,offset);		
	 }else{
		// otherwise add new node...
		int newIdx = mNodes.size();
		mNodes.resize(newIdx+1);
		mNodeName2IdxMap.Add(nodeName,newIdx);
		mNodes[newIdx].mName = nodeName;
		AddEdges(mNodes[newIdx],line,offset);
	 }
  }

  void Read(istream &fin){

	 string tempLine;
	 ALGNode<T> tempNode;
	 tempLine="";
	 do{
		fin.getline(readbuf,READ_BUFFER_SIZE);
		tempLine = readbuf;
		if (tempLine != ""){
		  AddLine(tempLine);
		}
		tempLine="";
	 }while(!(fin.eof()));	 
  }

  void Print(ALGNode<T> &Node,string &NodeName,ostream &fout){
	 fout<<NodeName<<"\t";
	 for(int eIdx = 0;eIdx < Node.mEdges.size();eIdx++){
		int nodeIdx = Node.mEdges[eIdx].mNodeIdx;
		string name= mNodes[nodeIdx].mName;
		fout<<name<<" ";
		string edgeStr = Node.mEdges[eIdx].mEdgeWeight.ToString();
		fout<<edgeStr<<" ";
	 }	 
  }

  void Print(ostream &fout){
	 String2IntMap::iterator it;
	 for(it = mNodeName2IdxMap.begin();it != mNodeName2IdxMap.end();it++){
		int nodeIdx = (*it).second;
		string nodeName = (*it).first;
		Print(mNodes[nodeIdx],nodeName,fout);
		fout<<endl;
	 }
  }

  void Bug();

};



// Some sugar for some standard kinds of graphs. 
typedef AdjacencyListGraph<AlignmentEdgeWt> OverlapperGraph;


#endif 








